package cn.labbook.bluetooth.aop;

import cn.labbook.bluetooth.annotation.SysLogBuilder;
import cn.labbook.bluetooth.aop.entity.LogAnParse;
import cn.labbook.bluetooth.common.ResultDto;
import cn.labbook.bluetooth.common.TokenManager;
import cn.labbook.bluetooth.constant.LogConstant;
import cn.labbook.bluetooth.constant.ResultConstant;
import cn.labbook.bluetooth.entity.Admin;
import cn.labbook.bluetooth.entity.SysLog;
import cn.labbook.bluetooth.exception.SysExceptionResolver;
import cn.labbook.bluetooth.service.ISysLogService;
import cn.labbook.bluetooth.shiro.TokenUser;
import cn.labbook.bluetooth.util.IPUtils;
import cn.labbook.bluetooth.util.SpelUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Administrator on 2018/4/26.
 * Description : 日志切面
 */
@Aspect
@Order(1)
@Component
public class LogsAspect {

    private String parseDesc(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        SysLogBuilder annotation = method.getAnnotation(SysLogBuilder.class);
        Object target = joinPoint.getTarget();
        Object[] args = joinPoint.getArgs();

        String desc = annotation.desc();

        Pattern pattern = Pattern.compile("#\\{[0-9a-zA-Z\\.]*}");
        Matcher matcher = pattern.matcher(desc);

        List<LogAnParse> spels = new ArrayList<>();
        while (matcher.find()) {
            LogAnParse logAnParse = new LogAnParse();
            String val = matcher.group();
            logAnParse.setCompleteContent(val);
            spels.add(logAnParse);
        }
        List<LogAnParse> list = SpelUtils.parse(target, spels, method, args);

        for (LogAnParse log : list) {
            String finalValue = log.getFinalValue();
            String completeContent = log.getFinalName(true);
            if (StringUtils.isNotBlank(completeContent)) {
                if (finalValue != null) {
                    if (finalValue == "") {
                        finalValue = "''";
                    }
                    desc = desc.replace(completeContent, finalValue);
                } else {
                    desc = desc.replace(completeContent, "null");
                }
            }
        }
        return desc;

    }

    @Autowired
    private ISysLogService iSysLogService;

    //正常情况下记录日志状态
    @Around(value = "@annotation(sysLog)")
    public Object around(ProceedingJoinPoint joinPoint, SysLogBuilder sysLog) throws Throwable {
        SysLog log = new SysLog();
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            actionEx(log, e);
            if (SysExceptionResolver.isAjax(getRequest())) {
                result = SysExceptionResolver.errorJsonResult((Exception) e);
            }

            throw e;
        } finally {
            createSimpleLog(log, joinPoint, sysLog);
            if (log == null) return result;
            String parseDesc = parseDesc(joinPoint);
            log.setLogDesc(parseDesc);
            actionFinally(log, result);
            return result;
        }

    }

    private void actionFinally(SysLog log, Object result) {
        if (log != null) {
            if (result != null) {
                if (result instanceof ResultDto) {
                    ResultDto dto = (ResultDto) result;
                    Integer code = dto.getCode();
                    String msg = dto.getMsg();
                    log.setLogStatus(code == ResultConstant.SUCCESS_CODE ? LogConstant.STATUS.SUCCESS : LogConstant.STATUS.FAIL);//操作成功
                    log.setLogMsg(msg);
                } else if (result instanceof String) {
                    log.setLogStatus(LogConstant.STATUS.SUCCESS);//操作成功
                }
            }
            iSysLogService.asynSave(log);
        }
    }


    private void actionEx(SysLog log, Throwable e) {
        if (log != null) {
            log.setLogStatus(LogConstant.STATUS.EXCEPTION);
            log.setLogMsg(e.getMessage());
            log.setLogEx(e.getClass().getName());
        }
    }

    private HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

    private void createSimpleLog(SysLog log, ProceedingJoinPoint joinPoint, SysLogBuilder annotation) {

        Signature signature = joinPoint.getSignature();

        HttpServletRequest request = getRequest();
        String requestURI = request.getRequestURI().substring(request.getRequestURI().indexOf("?") + 1);

        String content = annotation.value();
        String parseDesc = parseDesc(joinPoint);
        TokenUser tokenUser = TokenManager.getToken();
        Admin admin = tokenUser.getAdmin();
        if (admin != null) {
            Date date = new Date();
            log.setLogCreateDate(date);
            log.setAdminId(admin.getAdminId());
            log.setAdminName(admin.getAdminName());
            log.setIp(IPUtils.getRealIp(request));
            log.setLogContent(content);
            log.setMethodUri(requestURI);
            log.setLogDesc(parseDesc);
            log.setDeleteStatus(LogConstant.DEL_STATUS.UN_DEL);
            log.setMethodName(signature.toShortString());
        }
    }
}
